package com.lemon.cloud.admin.web;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.lemon.cloud.admin.dto.RoleDTO;
import com.lemon.cloud.comm.po.RoleApplication;
import com.lemon.cloud.admin.service.SysRoleService;
import com.lemon.cloud.admin.vo.RoleExcelVO;
import com.lemon.cloud.comm.constants.enums.DelFlagEnum;
import com.lemon.cloud.comm.constants.enums.LogBusType;
import com.lemon.cloud.comm.exception.BusinessException;
import com.lemon.cloud.comm.model.ResultMsg;
import com.lemon.cloud.comm.po.SysRole;
import com.lemon.cloud.core.excel.ExcelErrorMessage;
import com.lemon.cloud.log.annotation.SysLog;
import com.lemon.cloud.security.annotation.Inner;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

@RestController
@RequestMapping("role")
@Tag(name = "角色接口")
public class SysRoleController {

    @Autowired
    private SysRoleService roleService;

    @GetMapping("/list")
    @Operation(
            summary = "获取所有角色列表",
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation")
            }
    )
    public ResultMsg<List<SysRole>> getOrgTree() {
        return ResultMsg.resultSuccess(roleService.lambdaQuery()
                .select(SysRole::getId, SysRole::getCode, SysRole::getName, SysRole::getIsSys)
                .list());
    }

    /**
     * 分页查询
     *
     * @param page
     * @param role
     * @return
     */
    @Operation(
            summary = "分页查询角色",
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = IPage.class))})
            }
    )
    @GetMapping("/page")
    public ResultMsg<IPage<SysRole>> getRoleByPage(@ParameterObject Page<SysRole> page, @ParameterObject SysRole role) {
        return ResultMsg.resultSuccess(roleService.getRoleByPage(page, role));
    }

    /**
     * 修改角色
     *
     * @param sysRole
     * @return
     */
    @Operation(
            summary = "修改角色",
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation")
            }
    )
    @SysLog(value = "修改角色", businessType = LogBusType.MODIFY)
    @PutMapping
    @PreAuthorize("hasAnyAuthority('sys_role_edit')")
    public ResultMsg<SysRole> updateRole(@Parameter @Valid @RequestBody SysRole sysRole) {
        if (checkRole(sysRole.getId(), sysRole.getCode())) {
            return ResultMsg.resultFail("存在重复角色标识");
        }
        return roleService.updateRole(sysRole);
    }

    /**
     * 新增角色
     *
     * @param sysRole
     * @return
     */
    @Operation(
            summary = "新增角色",
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation")
            }
    )
    @SysLog(value = "新增角色", businessType = LogBusType.ADD)
    @PostMapping
    @PreAuthorize("hasAnyAuthority('sys_role_add')")
    public ResultMsg<SysRole> addRole(@Parameter @Valid @RequestBody SysRole sysRole) {
        if (checkRole(sysRole.getId(), sysRole.getCode())) {
            return ResultMsg.resultFail("存在重复角色标识");
        }
        return roleService.addRole(sysRole);
    }

    /**
     * 删除角色
     *
     * @param id
     * @return
     */
    @Operation(
            summary = "删除角色",
            parameters = {@Parameter(name = "id", description = "角色id", required = true,in = ParameterIn.PATH)},
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation")
            }
    )
    @SysLog(value = "删除角色", businessType = LogBusType.DELETE)
    @DeleteMapping("/{id:\\d+}")
    @PreAuthorize("hasAnyAuthority('sys_role_del')")
    public ResultMsg<Boolean> deleteRole(@PathVariable("id") Long id) {
        return roleService.deleteRole(id);
    }

    /**
     * 配置权限
     *
     * @param roleDTO
     * @return
     */
    @Operation(
            summary = "配置权限",
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation")
            }
    )
    @SysLog(value = "配置权限", businessType = LogBusType.MODIFY)
    @PutMapping("/menu")
    @PreAuthorize("hasAnyAuthority('sys_role_perm')")
    public ResultMsg<Boolean> saveRoleMenus(@Parameter @Valid @RequestBody RoleDTO roleDTO) {
        return roleService.saveRoleMenus(roleDTO);
    }

    /**
     * 导入角色
     */
    @Operation(
            summary = "导入角色",
            parameters = @Parameter(description = "上传的文件", required = true, schema = @Schema(type = "string", format = "binary")),
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation")
            }
    )
    @SysLog(value = "上传excel文件", businessType = LogBusType.IMPORT)
    @PostMapping("/import")
    @PreAuthorize("hasAnyAuthority('sys_role_import_export')")
    public ResultMsg importRole(HttpServletResponse response, @RequestBody MultipartFile file) throws IOException {
        List<ExcelErrorMessage> errorList = Lists.newArrayList();
        EasyExcel.read(file.getInputStream(), RoleExcelVO.class, new ReadListener<RoleExcelVO>() {
            List<SysRole> list = Lists.newArrayList();

            @Override
            public void invoke(RoleExcelVO o, AnalysisContext analysisContext) {
                SysRole role = new SysRole();
                BeanUtils.copyProperties(o, role);
                list.add(role);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                if (CollectionUtil.isEmpty(list)) {
                    throw new BusinessException("excel内容为空");
                }
                errorList.addAll(roleService.addBatch(list));
                list.clear();
            }
        }).sheet().doRead();
        if (CollectionUtil.isNotEmpty(errorList)) {
            return ResultMsg.resultFail(errorList);
        }
        return ResultMsg.resultSuccess();
    }

    @Operation(
            summary = "导出excel文件"
    )
    @SysLog(value = "导出excel文件", businessType = LogBusType.EXPORT)
    @GetMapping("/export")
    @PreAuthorize("hasAnyAuthority('sys_role_import_export')")
    public ResultMsg exportExcel(HttpServletResponse response) {
        try {
            List<SysRole> list = roleService.list(new LambdaQueryWrapper<SysRole>().select(SysRole::getName, SysRole::getCode, SysRole::getDescription)
                    .eq(SysRole::getDelFlag, DelFlagEnum.EXIST.getValue()));
            List<RoleExcelVO> excelVOS = Lists.newArrayList();
            for (SysRole role : list) {
                RoleExcelVO roleExcelVO = new RoleExcelVO();
                roleExcelVO.setCode(role.getCode());
                roleExcelVO.setName(role.getName());
                roleExcelVO.setDescription(role.getDescription());
                excelVOS.add(roleExcelVO);
            }
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("角色", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            // 这里需要设置不关闭流
            ServletOutputStream outputStream = response.getOutputStream();
            EasyExcel.write(outputStream, RoleExcelVO.class)
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .autoCloseStream(Boolean.FALSE)
                    .sheet()
                    .doWrite(excelVOS);
            outputStream.close();
            outputStream.flush();
        } catch (Exception e) {
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            return ResultMsg.resultFail("导出文件失败");
        }
        return null;
    }

    /**
     * 根据角色List查询权限
     *
     * @param roleCodeList
     * @return
     */
    @PostMapping("/getDSList")
    @Inner
    @Hidden
    public ResultMsg<List<RoleApplication>> getDSList(@RequestBody List<String> roleCodeList) {
        return ResultMsg.resultSuccess(roleService.getDSList(roleCodeList));
    }

    @Operation(
            summary = "通过角色编码获取数据权限集合",
            parameters = {@Parameter(name = "code",required = true,description = "角色编码",in = ParameterIn.QUERY)},
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = List.class))})
            }
    )
    @GetMapping("/getDateScopeByCode")
    public ResultMsg<List<RoleApplication>> getDateScopeByCode(@RequestParam String code) {
        return ResultMsg.resultSuccess(roleService.getDSList(Lists.newArrayList(code)));
    }

    /**
     * 配置数据权限
     *
     * @param roleData
     * @return
     */
    @Operation(
            summary = "配置数据权限",
            responses = {
                    @ApiResponse(responseCode = "200", description = "successful operation")
            }
    )
    @SysLog(value = "配置数据权限", businessType = LogBusType.MODIFY)
    @PutMapping("/data")
    @PreAuthorize("hasAnyAuthority('sys_role_data')")
    public ResultMsg<Boolean> saveRoleData(@Parameter @Valid @RequestBody List<RoleApplication> roleData) {
        for(RoleApplication item : roleData){
            if (item.getRoleId()==null){
                return ResultMsg.resultFail("角色id不能为空");
            }
        }
        return roleService.saveRoleData(roleData);
    }

    private boolean checkRole(Long id, String code) {
        long count = roleService.count(new LambdaQueryWrapper<SysRole>()
                .eq(!StrUtil.isEmpty(code), SysRole::getCode, code)
                .ne(id != null, SysRole::getId, id)
                .eq(SysRole::getDelFlag, DelFlagEnum.EXIST.getValue())
        );
        return count > 0;
    }
}
